<?php
/**
 * This file is part of the UXLabs project.
 *
 * (c) UXLabs project <http://code.uxlabs.me>
 *
 */

namespace uxl\app\api\components;

use yii\helpers\Json;
use yii\web\Response;

/**
 * 返回结果
 * @package uxl\app\api\components
 * @author ice deng <ice.deng@qq.com>
 */
class ResultResponse extends Response
{
    /**
     * @var int 处理状态
     */
    public $status = ResultStatus::SUCCESS;
    /**
     * @var string 错误信息
     */
    public $errmsg = '';
    /**
     * @var int 处理时间戳
     */
    public $timestamp;
    /**
     * @var string 请求者提交的值，原值返回
     */
    public $attach = '';
    /**
     * @var string 签名
     */
    public $sign = '';
    /**
     * @var mixed 处理结果集
     */
    public $result = '';
    /**
     * @var string 数据结果格式
     */
    public $format = RequestFormat::JSON;
    /**
     * @var string 字符集
     */
    public $charset = 'UTF-8';
    /**
     * @var string JSONP方式的回调方法名称
     */
    public $callback = 'response';
    /**
     * @var string xml格式时的根节点名称
     */
    public $xmlRootName = 'xml';

    /**
     * 数组转换为xml对象
     * @param string|array $body
     * @param \SimpleXMLElement $xmlRoot
     */
    public function arrayToXml($body, \SimpleXMLElement &$xmlRoot)
    {
        foreach ($body as $k => $v) {
            $key = is_numeric($k) ? "item$k" : $k;
            if (is_array($v)) {
                $sub = $xmlRoot->addChild("$key");
                $this->arrayToXml($v, $sub);
            } else {
                $xmlRoot->addChild("$key", "$v");
            }
        }
    }

    /**
     * 转换数据为xml字符串
     * @param array|string $data
     * @param string $root
     * @return string|bool
     */
    public function toXml($data, $root = 'xml')
    {
        $xmlRoot = new \SimpleXMLElement("<?xml version=\"1.0\" encoding=\"$this->charset\" ?><$root></$root>");
        $this->arrayToXml($data, $xmlRoot);
        $str = $xmlRoot->asXML();
        return $str === false ? '' : $str;
    }

    /**
     * 转换为JSON字符串
     * @param $data
     * @return string
     */
    public function toJson($data)
    {
        return Json::encode($data);
    }

    /**
     * 设置错误结果
     * @param $status
     * @param $errmsg
     * @param null $attach
     * @param null $format
     * @return ResultResponse
     */
    public function setError($status, $errmsg, $attach = null, $format = null)
    {
        return $this->setResult($status, null, $errmsg, $attach);
    }

    /**
     * 设置结果
     * @param $status
     * @param $result
     * @param null $errmsg
     * @param null $attach
     * @param null $timestamp
     * @param null $sign
     * @param null $format
     * @return $this
     */
    public function setResult($status, $result, $errmsg = null, $attach = null, $timestamp = null, $sign = null, $format = null)
    {
        $this->format = empty($format) ? $this->format : $format;
        $this->status = $status === null ? $this->status : $status;
        $this->result = $result === null ? $this->$result : $result;
        $this->sign = $sign === null ? $this->sign : $sign;
        $this->errmsg = $errmsg === null ? $this->errmsg : $errmsg;
        $this->attach = $attach === null ? $this->attach : $attach;
        $this->timestamp = $timestamp === null ? time() : $timestamp;
        $data = [
            'status' => $this->status,
            'result' => $this->result,
            'errmsg' => $this->errmsg,
            'timestamp' => $this->timestamp,
            'attach' => $this->attach,
            'sign' => $this->sign,
        ];
        $content = '';
        switch ($this->format) {
            case RequestFormat::JSON:
                $content = $this->toJson($data);
                break;
            case RequestFormat::XML:
                $content = $this->toXml($data);
                break;
            case RequestFormat::JSONP:
                $callback = \Yii::$app->request->get('callback', $this->callback);
                $content = $callback . '(' . $this->toJson($data) . ')';
                break;
        }
        $this->content = $content;
        $this->format = strtolower($this->format);
        return $this;
    }
}